package com.iflytek.jzcpx.procuracy.card.component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.jzcpx.procuracy.card.common.CardConstants;
import com.iflytek.jzcpx.procuracy.card.common.enums.CardFieldEnum;
import com.iflytek.jzcpx.procuracy.card.common.enums.XYRFieldNameEnum;
import com.iflytek.jzcpx.procuracy.card.entity.CardFile;
import com.iflytek.jzcpx.procuracy.card.entity.CardFormField;
import com.iflytek.jzcpx.procuracy.card.pojo.ElleResultData;
import com.iflytek.jzcpx.procuracy.card.service.CardFormFieldService;
import com.iflytek.jzcpx.procuracy.tools.elle.ElleTextTypeEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 办理阶段案卡填充组件
 *
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019-08-29 19:34
 */
@Component
public class FillHandleFormHelper extends AbstractFillFormHelper {
	private static final Logger logger = LoggerFactory.getLogger(FillHandleFormHelper.class);

	@Autowired
	private CardFormFieldService formFieldService;

	/**
	 * 抽取字段
	 *
	 * @param cardFileId       案卡文件id
	 * @param ajlbbm           赛威讯案件类别编码
	 * @param elleTextTypeEnum 文书类型
	 * @param elleResultData   elle引擎抽取结果
	 *
	 * @return
	 */
	public List<CardFormField> extractField(Long cardFileId, String ajlbbm, ElleTextTypeEnum elleTextTypeEnum,
			ElleResultData elleResultData) {
		List<CardFormField> fields = new ArrayList<>();

		List<ElleResultData.ExtractInfoVec> extractInfoVecList = elleResultData.getExtractInfoVec();
		if (CollectionUtils.isEmpty(extractInfoVecList)) {
			logger.info("要素引擎未抽取出数据");
			return null;
		}

		// 嫌疑人
		fields.addAll(
				extractXyrAndCbsjFields(cardFileId, ajlbbm, elleTextTypeEnum, extractInfoVecList, elleResultData));

		// 其他字段
		fields.addAll(extractOthers(cardFileId, ajlbbm, elleTextTypeEnum, elleResultData));

		return fields;
	}

	/** 抽取其他字段 */
	private Collection<? extends CardFormField> extractOthers(Long cardFileId, String ajlbbm,
			ElleTextTypeEnum elleTextTypeEnum, ElleResultData elleResultData) {
		List<CardFormField> newFields = new ArrayList<>();
		// 只抽取 CardFieldEnum 中配置的字段
		for (CardFieldEnum cardFieldEnum : CardFieldEnum.values()) {
			Collection<String> stbms = cardFieldEnum.getStbm();
			String zdmc = cardFieldEnum.getZdmc();
			Collection<ElleTextTypeEnum> supportElleTextTypeEnums = cardFieldEnum.getSupportElleTextType();

			// 该字段无法从该文书中被抽取
			if (!supportElleTextTypeEnums.contains(elleTextTypeEnum)) {
				continue;
			}

			for (String stbm : stbms) {
				ElleResultData.Item item = cardFieldEnum.getElleFieldExtractor().apply(elleResultData);
				if (item == null) {
					continue;
				}

				// 对字段文本值进行格式化，例如：抽取到出生日期1990年7月10日，则格式化为1990-07-10,
				// 如果字段文本值不符合规范(如: 19x4年7月10日)则返回空, 此时不再回填
				String zdwbz = cardFieldEnum.convertZdwbz(item.getMean());
				if (StringUtils.isBlank(zdwbz)) {
					continue;
				}

				CardFormField cardFormField = buildXyrBaseField(cardFileId, stbm);
				cardFormField.setZdmc(zdmc);
				cardFormField.setZdwbz(zdwbz);
				String zdbmz = cardFieldEnum.convertZdbmzForStore(zdwbz, zdbmConfig);
				cardFormField.setZdbmz(zdbmz);
				// 记录字段位置, 便于差异页面做高亮效果
				cardFormField.setRemark(new CardFormFieldRemark(item).toRemarkString());

				newFields.add(cardFormField);
			}
		}

		logger.info("抽取其他字段完成, 共抽取[ {} ]条数据.", CollectionUtils.size(newFields));
		return newFields;
	}

	/**
	 * 回填小案卡表单(文书编写/外来文书)
	 *
	 * @param ajlbbm          赛威讯案件类别编码
	 * @param bdjg            表单结构
	 * @param fieldAndFileMap 抽取出的字段
	 *
	 * @return
	 */
	public JSONObject fill(String ajlbbm, JSONObject bdjg, Map<CardFormField, CardFile> fieldAndFileMap) {
		logger.info("开始表单回填");
		if (MapUtils.isEmpty(fieldAndFileMap)) {
			return bdjg;
		}

		// 填充嫌疑人数据
		fillXyr(fieldAndFileMap, bdjg, ajlbbm, false);

		// 填充其他字段
		fillOthers(fieldAndFileMap, bdjg, false);

		logger.info("办理阶段案卡表单字段回填结束");
		return bdjg;
	}

	/**
	 * 全案卡表单字段回填, 需要填写到znht(智能回填)字段
	 *
	 * @param bmsah      部门受案号
	 * @param bdjg       表单结构
	 * @param ajlbbm     案件列表编码
	 * @param fileFields 案卡文件 : 表单字段
	 *
	 * @return
	 */
	public JSONObject fullFill(String bmsah, JSONObject bdjg, String ajlbbm,
			Map<CardFile, List<CardFormField>> fileFields) {
		logger.info("开始全案卡表单字段回填, bmsah: {}", bmsah);

		// 获取字段数据与案卡文件对应关系
		Map<CardFormField, CardFile> fieldFileMap = new HashMap<>();
		Iterator<Map.Entry<CardFile, List<CardFormField>>> iterator = fileFields.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<CardFile, List<CardFormField>> entry = iterator.next();
			CardFile file = entry.getKey();
			List<CardFormField> fields = entry.getValue();
			if (file == null || CollectionUtils.isEmpty(fields)) {
				iterator.remove();
				continue;
			}

			for (CardFormField field : fields) {
				fieldFileMap.put(field, file);
			}
		}

		// 回填嫌疑人
		fillXyr(fieldFileMap, bdjg, ajlbbm, true);

		// 回填其他字段
		fillOthers(fieldFileMap, bdjg, true);

		return bdjg;
	}

	/**
	 * 填充其他字段(CardFieldEnum中配置的字段)
	 *
	 * @param fieldAndFileMap 已抽取的字段
	 * @param bdjg            待回填的赛威讯表单结构
	 * @param isFullFill      是否是全案卡字段回填
	 */
	private void fillOthers(Map<CardFormField, CardFile> fieldAndFileMap, JSONObject bdjg, boolean isFullFill) {
		logger.info("开始回填其他表单字段, fieldSize[ {} ]", MapUtils.size(fieldAndFileMap));

		// 表单中字段数据的 id(赛威讯数据的id)需要更新到我们的数据库中,
		// 便于在差异比对页面根据表单中字段数据的 id获取对应的我们的字段
		Map<String, List<Long>> bdjgIdAndFormFieldId = new HashMap<>();

		// 表单结构按表名和字段名称分组
		Map<String, JSONObject> stbmMap = groupByStbm(bdjg);
		// 表单字段数据按表名+字段名称分组
		Map<String, Map<String, JSONObject>> stbmAndZdmcMap = groupZdsjByStbmAndZdmc(bdjg);

		// 已抽取字段按 表名:字段名:字段 分组
		Map<String, Map<String, List<CardFormField>>> fieldsMap = fieldAndFileMap.keySet().stream()
				.collect(Collectors.groupingBy(CardFormField::getStbm, Collectors.groupingBy(CardFormField::getZdmc)));

		// 只回填 CardFieldEnum 中配置的字段
		for (CardFieldEnum fieldEnum : CardFieldEnum.values()) {
			Collection<String> stbms = fieldEnum.getStbm();
			String zdmc = fieldEnum.getZdmc();
			for (String stbm : stbms) {

				// 找到对应的已抽取字段
				List<CardFormField> zdmcFields = getMapValue(fieldsMap, stbm, zdmc);
				if (CollectionUtils.isEmpty(zdmcFields)) {
					continue;
				}
				CardFormField cardFormField = zdmcFields.get(0);

				// 找到对应的表单字段
				JSONObject zdsjJson = getMapValue(stbmAndZdmcMap, stbm, zdmc);
				if (zdsjJson == null) {
					continue;
				}

				// 填充字段
				if (!isNeedFill(zdsjJson)) {
					// 如果变更前/变更后字段值不为空则不需要填充
					continue;
				}

				// 设置数据标识字段
				JSONObject cbsj = stbmMap.get(stbm);
				setSjbs(cbsj);
				// 设置变更时间
				fillBgsj(zdsjJson);

				if (isFullFill) {
					fillZnhtWithSingleValue(zdsjJson, cardFormField, fieldAndFileMap.get(cardFormField));
				} else {
					String zdwbz = StringUtils.defaultString(cardFormField.getZdwbz(), "");
					zdsjJson.put("bghzdwbz", zdwbz);
					String zdbmz = CardFieldEnum.convertZdbmzForBdjg(cardFormField);
					String zdlx = zdsjJson.getString("zdlx");
					// 文本型类型 编码值填写上文本值
					if (CardConstants.TEXT_ZDLX.contains(zdlx)) {
						zdsjJson.put("bghzdbmz", zdbmz);
					} else {
						if (!zdbmz.equals(zdwbz)) {
							zdsjJson.put("bghzdbmz", zdbmz);
						}
					}
				}

				// 记录下表单结构 id 和我们的字段 id 对应关系
				String zdsjId = cbsj.getString("id");
				List<Long> formFieldIds = bdjgIdAndFormFieldId.getOrDefault(zdsjId, new ArrayList<>());
				bdjgIdAndFormFieldId.put(zdsjId, formFieldIds);
				formFieldIds.add(cardFormField.getId());
			}
		}

		// 将表单中的字段 id(赛威讯数据的id) 保存到我们的数据库
		if (MapUtils.isNotEmpty(bdjgIdAndFormFieldId)) {
			for (Map.Entry<String, List<Long>> entry : bdjgIdAndFormFieldId.entrySet()) {
				String bdjgId = entry.getKey();
				List<Long> formFieldIds = entry.getValue();
				formFieldService.updateBdjgId(formFieldIds, bdjgId);
			}
		}
	}

	/** 回调小案卡-嫌疑人 */
	private void fillXyr(Map<CardFormField, CardFile> fieldAndFileMap, JSONObject bdjgJson, String ajlbbm,
			boolean isFullFill) {
		logger.info("开始回填嫌疑人表单字段, fieldSize[ {} ]", MapUtils.size(fieldAndFileMap));

		String xyrTableName = parseXyrTableName(ajlbbm);
		if (StringUtils.isBlank(xyrTableName)) {
			logger.warn("无法根据案件类别编码：{} 获取对应的嫌疑人表名", ajlbbm);
			return;
		}

		// 首先将表单中的嫌疑人数据按证件号分组
		Map<PersonIdentifier, JSONObject> personBdjgMap = groupBdjgByPerson(bdjgJson, xyrTableName);
		if (MapUtils.isEmpty(personBdjgMap)) {
			logger.info("原始表单结构中未能获取到人员标识，嫌疑人回填结束。");
			return;
		}

		// 将已保存的表单字段数据按证件号进行分组
		Map<PersonIdentifier, List<CardFormField>> personFieldMap = groupFieldsByPerson(fieldAndFileMap.keySet(),
				xyrTableName);
		if (MapUtils.isEmpty(personFieldMap)) {
			logger.info("已保存的字段中没有人员标识, 嫌疑人回填结束。");
			return;
		}

		// 遍历表单中的证件号码，根据证件号码获取已保存字段并回填
		for (Map.Entry<PersonIdentifier, JSONObject> personBdjgEntry : personBdjgMap.entrySet()) {
			PersonIdentifier personIdentifier = personBdjgEntry.getKey();
			String bdjgId = personIdentifier.getBdjgId();
			JSONObject xyrJson = personBdjgEntry.getValue();
			if (xyrJson == null) {
				continue;
			}

			// 获取对应的已保存表单字段
			List<CardFormField> formFields = getFieldsOfPerson(personIdentifier, personFieldMap);
			if (CollectionUtils.isEmpty(formFields)) {
				continue;
			}

			// 首先要把表单结构中本条数据的 id(赛威讯的数据标识) 保存到我们的数据库中, 以便后面差异化比对界面获取对应的字段数据
			formFieldService.updateBdjgId(formFields.stream().map(CardFormField::getId).collect(Collectors.toList()),
					bdjgId);

			// 将表单字段按字段名称分组, 方便后面回填时按名称查找
			Map<String, JSONObject> zdmcMap = new HashMap<>();
			for (Object zdsjObj : xyrJson.getJSONArray("zdsj")) {
				JSONObject zdsjJson = (JSONObject) zdsjObj;
				zdmcMap.put(zdsjJson.getString("zdmc"), zdsjJson);
			}

			// todo 回填从表数据

			// 遍历已保存字段进行回填
			Map<String, List<CardFormField>> zdmcFieldMap = formFields.stream()
					.collect(Collectors.groupingBy(CardFormField::getZdmc));
			for (Map.Entry<String, List<CardFormField>> fieldEntry : zdmcFieldMap.entrySet()) {
				String zdmc = fieldEntry.getKey();
				List<CardFormField> fields = fieldEntry.getValue();
				JSONObject zdsj = zdmcMap.get(zdmc);
				// 如果字段不需要回填，则不回填该字段
				/*
				 * if (!isNeedFill(zdsj) || CollectionUtils.isEmpty(fields)) { continue; }
				 */
				if (CollectionUtils.isEmpty(fields) || null == zdsj || !isNeedFill(zdsj)) {
					continue;
				}
				// 设置变更时间
				fillBgsj(zdsj);

				// 设置数据标识字段
				setSjbs(xyrJson);

				if (isFullFill) {
					fillZnhtWithMultiValue(zdsj, fields, fieldAndFileMap);
				} else {
					CardFormField field = fields.get(0);
					String zdwbz = field.getZdwbz();
					String zdbmz = XYRFieldNameEnum.convertZdbmzForBdjg(field);
					zdsj.put("bghzdwbz", StringUtils.defaultString(zdwbz, ""));

					String zdlx = zdsj.getString("zdlx");
					// 文本型类型 编码值填写上文本值
					if (CardConstants.TEXT_ZDLX.contains(zdlx)) {
						zdsj.put("bghzdbmz", zdbmz);
					} else {
						if (!zdbmz.equals(zdwbz)) {
							zdsj.put("bghzdbmz", zdbmz);
						}
					}
				}
			}

			// 回填从表数据

			JSONArray cbsjArray = xyrJson.getJSONArray("cbsj");
			if (!cbsjArray.isEmpty()) {
				for (Object cbsjObj : cbsjArray) {
					JSONObject cbsjJson = (JSONObject) cbsjObj;
					JSONArray zdsjArray = cbsjJson.getJSONArray("zdsj");

					// 将从表表单字段按字段名称分组, 方便后面回填时按名称查找
					Map<String, JSONObject> cbzdmcMap = new HashMap<>();
					for (Object zdsjObj : zdsjArray) {
						JSONObject zdsjJson = (JSONObject) zdsjObj;
						cbzdmcMap.put(zdsjJson.getString("zdmc"), zdsjJson);
					}

					for (Map.Entry<String, List<CardFormField>> fieldEntry : zdmcFieldMap.entrySet()) {
						String zdmc = fieldEntry.getKey();
						List<CardFormField> fields = fieldEntry.getValue();
						JSONObject zdsj = cbzdmcMap.get(zdmc);
						/*
						 * if("QZCS".equals(zdmc)) { System.out.println(); }
						 */
						// 如果字段不需要回填，则不回填该字段
						if (CollectionUtils.isEmpty(fields) || null == zdsj || !isNeedFill(zdsj)) {
							continue;
						}

						// 设置变更时间
						fillBgsj(zdsj);

						// 设置数据标识字段
						setSjbs(cbsjJson);

						if (isFullFill) {
							fillZnhtWithMultiValue(zdsj, fields, fieldAndFileMap);
						} else {
							CardFormField field = fields.get(0);
							String zdwbz = field.getZdwbz();
							String zdbmz = XYRFieldNameEnum.convertZdbmzForBdjg(field);
							zdsj.put("bghzdwbz", StringUtils.defaultString(zdwbz, ""));
							String zdlx = zdsj.getString("zdlx");
							// 文本型类型 编码值填写上文本值
							if (CardConstants.TEXT_ZDLX.contains(zdlx)) {
								zdsj.put("bghzdbmz", zdbmz);
							} else {
								if (!zdbmz.equals(zdwbz)) {
									zdsj.put("bghzdbmz", zdbmz);
								}
							}
						}
					}

				}
			}
		}
	}

	/** 将已保存的字段数据按证件号码进行分组 */
	private Map<PersonIdentifier, List<CardFormField>> groupFieldsByPerson(Collection<CardFormField> cardFormFields,
			String xyrTableName) {
		// 配置文件中的所有嫌疑人表名称
		List<String> suppectTableNames = listAllSuppectTableNames();

		Map<PersonIdentifier, List<CardFormField>> personFieldMap = new HashMap<>();

		/*
		 * Map<String, List<CardFormField>> primaryKeyFields = cardFormFields.stream()
		 * .filter(f -> f.getStbm().equals(xyrTableName) ||
		 * suppectTableNames.contains(f.getStbm()))
		 * .collect(Collectors.groupingBy(CardFormField::getPrimaryKey));
		 */
		// 先按primaryKey分组，这样同一分组下的多个字段就来自同一条数据, 为提高兼容性, 也会对配置文件的嫌疑人表名进行验证
		Map<String, List<CardFormField>> primaryKeyFields = cardFormFields.stream()
				.collect(Collectors.groupingBy(CardFormField::getPrimaryKey));

		primaryKeyFields = this.sortByKey(primaryKeyFields);

		// 再用分组下的姓名和证件号字段组成人员标识
		for (List<CardFormField> formFields : primaryKeyFields.values()) {
			// 找到证件号和姓名字段
			CardFormField xmField = null;
			CardFormField zjhmField = null;
			for (CardFormField formField : formFields) {
				if (formField.getZdmc().equalsIgnoreCase(XYRFieldNameEnum.ZJHM.name())) {
					zjhmField = formField;
				}
				if (formField.getZdmc().equalsIgnoreCase(XYRFieldNameEnum.XM.name())) {
					xmField = formField;
				}
			}

			// 将分组内的字段按人员标识保存到 map
			if (xmField != null || zjhmField != null) {
				String xmValue = xmField == null ? "" : xmField.getZdwbz();
				String zjhmValue = zjhmField == null ? "" : zjhmField.getZdwbz();
				PersonIdentifier personIdentifierKey = new PersonIdentifier(xmValue, zjhmValue);
				List<CardFormField> list = personFieldMap.get(personIdentifierKey);
				if (CollectionUtils.isNotEmpty(list)) {
					formFields.addAll(list);
					personFieldMap.put(personIdentifierKey, formFields);
				} else {
					personFieldMap.put(new PersonIdentifier(xmValue, zjhmValue), formFields);
				}
			}
		}
		return personFieldMap;
	}

	private <K extends Comparable<? super K>, V> Map<K, V> sortByKey(Map<K, V> map) {
		Map<K, V> result = new LinkedHashMap<K, V>();
		map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey())
				.forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
		return result;
	}

	/** 将表单中的嫌疑人数据进行分组 */
	private Map<PersonIdentifier, JSONObject> groupBdjgByPerson(JSONObject bdjgJson, String xyrTableName) {
		// 配置文件中保存的所有嫌疑人表名称
		List<String> configedXyrTableNames = listAllSuppectTableNames();

		Map<PersonIdentifier, JSONObject> zjhmBdjgMap = new HashMap<>();
		String name = null;
		String certificatesId = null;
		// 取从表数据
		for (Object cbsjObj : bdjgJson.getJSONArray("cbsj")) {
			JSONObject cbsjJson = (JSONObject) cbsjObj;
			String stbm = cbsjJson.getString("stbm");
			// 判断实体表名等于嫌疑人表名, 为保证兼容异常情况, 也验证配置文件中的嫌疑人表名
			if (stbm.equals(xyrTableName) || configedXyrTableNames.contains(stbm)) {
				// 获取字段数据
				JSONArray zdsjArray = cbsjJson.getJSONArray("zdsj");
				for (Object zdsjObj : zdsjArray) {
					JSONObject zdsjJson = (JSONObject) zdsjObj;
					String zdValue = StringUtils.firstNonEmpty(zdsjJson.getString("bgqzdbmz"),
							zdsjJson.getString("bgqzdwbz"), zdsjJson.getString("bghzdbmz"),
							zdsjJson.getString("bghzdwbz"));
					// 判断字段名称等于证件号码
					if (zdsjJson.getString("zdmc").equalsIgnoreCase(XYRFieldNameEnum.ZJHM.name())) {
						certificatesId = zdValue;
					}
					// 判断字段名称等于姓名
					if (zdsjJson.getString("zdmc").equalsIgnoreCase(XYRFieldNameEnum.XM.name())) {
						name = zdValue;
					}

					// 读取过姓名和证件号之后跳出循环, 节省资源
					if (name != null && certificatesId != null) {
						break;
					}
				}

				// 将嫌疑人表单按姓名+证件号分组, 同时记录下表单的 id 字段以便在差异化比对页面定位数据
				String bdjgId = cbsjJson.getString("id");
				zjhmBdjgMap.put(new PersonIdentifier(name, certificatesId, bdjgId), cbsjJson);

				// 重置姓名和证件号, 进行下一次循环
				name = null;
				certificatesId = null;
			}
		}
		return zjhmBdjgMap;
	}

	/**
	 * 填充智能回填字段(单一字段值)
	 *
	 * @param zdsj      字段json
	 * @param formField 已保存的字段值
	 * @param cardFile  字段值来自的文件
	 */
	private void fillZnhtWithSingleValue(JSONObject zdsj, CardFormField formField, CardFile cardFile) {
		String zdlx = zdsj.getString("zdlx");
		JSONObject znhtJSON = (JSONObject) zdsj.getJSONArray("znht").get(0);
		JSONObject sjxJSON = (JSONObject) znhtJSON.getJSONArray("sjx").get(0);

		doFillZnht(znhtJSON, zdlx, sjxJSON, formField, cardFile);
	}

	/**
	 * 填充智能回填字段(多个字段值)
	 *
	 * @param zdsj         字段 json
	 * @param formFields   已抽取的字段值
	 * @param fieldFileMap 字段值与来自的文件对应关系
	 */
	private void fillZnhtWithMultiValue(JSONObject zdsj, List<CardFormField> formFields,
			Map<CardFormField, CardFile> fieldFileMap) {
		String zdlx = zdsj.getString("zdlx");
		String zdmc = zdsj.getString("zdmc");
		/*
		 * if ("ZASNL".equals(zdmc)) { System.out.println(); }
		 */
		JSONArray znhtArray = zdsj.getJSONArray("znht");
		JSONObject znht = (JSONObject) znhtArray.get(0);
		if (StringUtils.isNotEmpty(zdsj.getString("bgqzdwbz"))) {
			String bgqzdwbz = zdsj.getString("bgqzdwbz");
			String bghzdwbz = formFields.get(0).getZdwbz();
			// 变更前后文本值一样
			if (bgqzdwbz.equals(bghzdwbz)) {
				return;
			}

		}

		if (StringUtils.isNotEmpty(zdsj.getString("bgqzdbmz"))) {
			String bgqzdbmz = zdsj.getString("bgqzdbmz");
			String bghzdbmz = formFields.get(0).getZdbmz();
			if (StringUtils.isEmpty(bghzdbmz)) {
				bghzdbmz = formFields.get(0).getZdwbz();
			}
			// 变更前后文本值一样
			if (bgqzdbmz.equals(bghzdbmz)) {
				return;
			}

		}

		// 相同的字段值只回填一次, 因此先过滤出值不同的字段
		Collection<CardFormField> distinctFields = formFields.stream()
				.collect(Collectors.toMap(CardFormField::getZdwbz, p -> p, (p, q) -> p)).values();
		List<CardFormField> fields = new ArrayList<>(distinctFields);
		String bghzdbmz = formFields.get(0).getZdbmz();
		String bghzdwbz = formFields.get(0).getZdwbz();
		zdsj.put("bghzdbmz", bghzdbmz);
		zdsj.put("bghzdwbz", bghzdwbz);

		// 每个字段的需要一个数据项(sjx)对象去存储
		for (int i = 0; i < fields.size(); i++) {
			CardFormField formField = fields.get(i);
			CardFile cardFile = fieldFileMap.get(formField);

			// 如果一个字段有多个值，在回填时需要将第一个值直接回填回表单，后续的值需要先克隆表单字段再回填
			JSONObject znhtJson = znht;
			if (i > 0) {
				znhtJson = SerializationUtils.clone(znht);
				znhtArray.add(znhtJson);
			}
			JSONObject sjxJson = (JSONObject) znhtJson.getJSONArray("sjx").get(0);

			doFillZnht(znhtJson, zdlx, sjxJson, formField, cardFile);
		}
	}

	/**
	 * 回填 znht 字段
	 *
	 * @param znhtJson  待回填的智能回填对象
	 * @param zdlx      字段类型
	 * @param sjxJson   数据项
	 * @param formField 已抽取的字段数据
	 * @param cardFile  已抽取的字段数据来源
	 */
	private void doFillZnht(JSONObject znhtJson, String zdlx, JSONObject sjxJson, CardFormField formField,
			CardFile cardFile) {
		fillWjInfo(znhtJson, cardFile);

		String zdwbz = formField.getZdwbz();
		String zdbmz = formField.getZdbmz();
		// 对于某些类型的字段, 需要将对应编码值填入bm字段, 对应文本值填入wb字段，而其他类型的字段均将值填入bm
		if (CardConstants.FILL_BM_ZDLX.contains(zdlx)) {
			fillBmAndWb(sjxJson, zdwbz, zdbmz);
		} else {
			fillBmAndWb(sjxJson, zdwbz, zdwbz);
		}
	}

	/**
	 * 回填文件信息(wjbm, wjlx, wjmc)
	 *
	 * @param znhtJson 待回填的表单对象
	 * @param cardFile 文件信息
	 */
	private void fillWjInfo(JSONObject znhtJson, CardFile cardFile) {
		znhtJson.put("wjbm",
				StringUtils.defaultString(StringUtils.firstNonBlank(cardFile.getWsslbh(), cardFile.getJzwjh()), ""));
		// WS：文书，JZ：电子卷宗
		znhtJson.put("wjlx", "WS");
		znhtJson.put("wjmc", cardFile.getWsmc());
	}

	/**
	 * 设置 wb 和 bm 字段值
	 *
	 * @param sjxJson 待回填的表单对象
	 * @param zdwbz   待回填的 wb 值
	 * @param zdbmz   待回填的 bm 值
	 */
	private void fillBmAndWb(JSONObject sjxJson, String zdwbz, String zdbmz) {
		sjxJson.put("wb", zdwbz);
		sjxJson.put("bm", zdbmz);
	}
}
